﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using System.Device.Location;

using Microsoft.Phone.Controls.Maps;
using Microsoft.Phone.Controls.Maps.Core;
using System.Windows.Navigation;
using DoveSiButta.DSBServiceReference1;
using DoveSiButta.Models;
using System.Collections.ObjectModel;
using System.Data.Services.Client;

namespace DoveSiButta
{
    public partial class MapPage : PhoneApplicationPage
    {

        //Box selectedItem;

        // Public collection used for data binding.
        //public ObservableCollection<Box> Boxes;

        //Location

        AppSettings settings;
        

        GeoCoordinateWatcher watcher;
        string accuracyText = "";


        //public MapPage()
        //{
        //    InitializeComponent();
        //}


        // When page is navigated to set data context to selected item in list
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            App.mapPage = this; //controllare
            string selectedIndex = "";
            if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
            {
                int index = int.Parse(selectedIndex);
                LoadBoxesForType(App.ViewModel.RifiutiTypes[index].code);

                //this.Boxes = App.ViewModel.Boxes;

                foreach (Box b in Boxes)
                {

                    CreateBoxPushpin(b);
                }

                //BoxesInfoTextBlock.Text = Boxes.Count.ToString(); //debug
            }

            //this.Loaded += new RoutedEventHandler(MapPage_Loaded);

            if (settings.UseLocationSetting == true)
            {
                StartLocationService(GeoPositionAccuracy.Default);
            }
            else
            {
                //tolgo il pushpin della userlocation
                PushpinModel pushpinToRemove = Pushpins.Where(p => p.TypeName == "UserLocation").FirstOrDefault();
                Pushpins.Remove(pushpinToRemove);
            }

        }

        //// Load data for the ViewModel Items
        //private void MapPage_Loaded(object sender, RoutedEventArgs e)
        //{
        //    if (!App.ViewModel.IsBoxDataLoaded)
        //    {
        //        App.ViewModel.RifiutiTypes[index].code();
        //    }
        //}

        #region Consts

        /// <value>Default map zoom level.</value>
        private const double DefaultZoomLevel = 16.0;

        /// <value>Default map zoom level if user does not enable location services</value>
        private const double DefaultZoomLevelNoUserLocation = 6.0;

        /// <value>Maximum map zoom level allowed.</value>
        private const double MaxZoomLevel = 21.0;

        /// <value>Minimum map zoom level allowed.</value>
        private const double MinZoomLevel = 1.0;

        #endregion

        #region Fields

        /// <value>Provides credentials for the map control.</value>
        private readonly CredentialsProvider _credentialsProvider = new ApplicationIdCredentialsProvider(App.Id);

        /// <value>Default location coordinate.</value>
        private static readonly GeoCoordinate DefaultLocation = new GeoCoordinate(42.378836, 13.601074);
        private static GeoCoordinate UserLocation = DefaultLocation;

        /// <value>Collection of pushpins available on map.</value>
        private readonly ObservableCollection<PushpinModel> _pushpins = new ObservableCollection<PushpinModel>
        {
            new PushpinModel
            {
                Location = UserLocation,
                TypeName = "UserLocation",
                Icon = new Uri("/Resources/Icons/Pushpins/PushpinLocation.png", UriKind.Relative),
                Address = "La tua posizione"
            }
        };

        /// <value>Map zoom level.</value>
        private double _zoom;

        /// <value>Map center coordinate.</value>
        private GeoCoordinate _center;

        #endregion

        #region Properties

        public bool HasDirections
        {
            get
            {
                // TODO : Return true only if has directions.

                return true;
            }
        }

        /// <summary>
        /// Gets the credentials provider for the map control.
        /// </summary>
        public CredentialsProvider CredentialsProvider
        {
            get { return _credentialsProvider; }
        }

        /// <summary>
        /// Gets or sets the map zoom level.
        /// </summary>
        public double Zoom
        {
            get { return _zoom; }
            set
            {
                //var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value));
                //if (_zoom != coercedZoom)
                //{
                //    _zoom = value;
                //    NotifyPropertyChanged("Zoom");
                //}

                if (_zoom != value)
                {
                    _zoom = value;
                    NotifyPropertyChanged("Zoom");
                }

            }
        }

        /// <summary>
        /// Gets or sets the map center location coordinate.
        /// </summary>
        public GeoCoordinate Center
        {
            get { return _center; }
            set
            {
                if (_center != value)
                {
                    _center = value;
                    NotifyPropertyChanged("Center");
                }
            }
        }

        /// <summary>
        /// Gets a collection of pushpins.
        /// </summary>
        public ObservableCollection<PushpinModel> Pushpins
        {
            get { return _pushpins; }
        }

        #endregion

        #region Tasks

        private void InitializeDefaults()
        {
            if (settings.UseLocationSetting == true)
            {
                Zoom = DefaultZoomLevel;
            }
            else
            {
                Zoom = DefaultZoomLevelNoUserLocation;
            }

            Center = UserLocation;
        }

        private void ChangeMapMode()
        {
            // TODO : Change map view mode.
            if (Map.Mode is AerialMode)
            {
                Map.Mode = new RoadMode();
            }
            else
            {
                Map.Mode = new AerialMode(true);
            }
        }

        private void CenterLocation()
        {
            // Center map to default location.
            Center = UserLocation;

            // Reset zoom default level.
            if (settings.UseLocationSetting == true)
            {
                Zoom = DefaultZoomLevel;
            }
            else
            {
                Zoom = DefaultZoomLevelNoUserLocation;
            }
        }

        //private void CenterPushpinsPopup(Point touchPoint)
        //{
        //    // Reposition the pushpins popup to the center of the touch point.
        //    Canvas.SetTop(PushpinPopup, touchPoint.Y - ListBoxPushpinCatalog.Height / 2);
        //}

        private void CreateBoxPushpin(Box selected)
        {
            GeoCoordinate location = new GeoCoordinate(selected.Latitude, selected.Longitude);
            var pushpinPrototype = new PushpinModel(); // selectedItem as PushpinModel;
            var pushpin = pushpinPrototype.Clone(location);
            pushpin.TypeName = "PushpinRestaurant";
            pushpin.Icon = new Uri("/Resources/Icons/Pushpins/PushpinBinBlack.png", UriKind.Relative);
            pushpin.BoxID = selected.BoxID.ToString();
            pushpin.Address = selected.Address;
            Pushpins.Add(pushpin);
        }
        /*
        private void CreateNewPushpin(object selectedItem, Point point)
        {
            // Translate the map viewport touch point to a geo coordinate.
            GeoCoordinate location;
            Map.TryViewportPointToLocation(point, out location);

            // Use the geo coordinate calculated to add a new pushpin,
            // based on the selected pushpin prototype,
            var pushpinPrototype = selectedItem as PushpinModel;
            var pushpin = pushpinPrototype.Clone(location);

            Pushpins.Add(pushpin);
        }
        */
        private void Pushpin_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {


            var _ppmodel = sender as Pushpin;
            ContextMenu contextMenu =
                ContextMenuService.GetContextMenu(_ppmodel);
            contextMenu.DataContext = Pushpins.Where
                (c => (c.Location
                    == _ppmodel.Location)).FirstOrDefault();
            if (contextMenu.Parent == null)
            {
                contextMenu.IsOpen = true;
            }

            //var pushpin = sender as Pushpin;
            
            //var pushpin = sender as Pushpin; // questo era il codice originale

            // Center the map on a pushpin when touched.
            Center = _ppmodel.Location;
            //selectedIndex = _ppmodel.BoxID;
            //selectedIndex = int.Parse( pushpin.Name); //TODO: il pushpin dovrebbe contenere anche l'ID del box
        }

        private void CalculateRoute()
        {
            // TODO : Calculate a route.
        }

        #endregion


        #region Application Location Logic

        /// <summary>
        /// Helper method to start up the location data acquisition
        /// </summary>
        /// <param name="accuracy">The accuracy level </param>
        private void StartLocationService(GeoPositionAccuracy accuracy)
        {
            // Reinitialize the GeoCoordinateWatcher
            StatusTextBlock.Text = "starting, " + accuracyText;
            watcher = new GeoCoordinateWatcher(accuracy);
            watcher.MovementThreshold = 20;

            // Add event handlers for StatusChanged and PositionChanged events
            watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
            watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);

            // Start data acquisition
            watcher.Start();
        }

        /// <summary>
        /// Handler for the StatusChanged event. This invokes MyStatusChanged on the UI thread and
        /// passes the GeoPositionStatusChangedEventArgs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MyStatusChanged(e));

        }
        /// <summary>
        /// Custom method called from the StatusChanged event handler
        /// </summary>
        /// <param name="e"></param>
        void MyStatusChanged(GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Disabled:
                    // The location service is disabled or unsupported.
                    // Alert the user
                    StatusTextBlock.Text = "location is unsupported on this device";
                    break;
                case GeoPositionStatus.Initializing:
                    // The location service is initializing.
                    // Disable the Start Location button
                    StatusTextBlock.Text = "initializing location service," + accuracyText;
                    break;
                case GeoPositionStatus.NoData:
                    // The location service is working, but it cannot get location data
                    // Alert the user and enable the Stop Location button
                    StatusTextBlock.Text = "data unavailable," + accuracyText;
                    break;
                case GeoPositionStatus.Ready:
                    // The location service is working and is receiving location data
                    // Show the current position and enable the Stop Location button
                    StatusTextBlock.Text = "receiving data, " + accuracyText;
                    break;

            }
        }

        /// <summary>
        /// Handler for the PositionChanged event. This invokes MyStatusChanged on the UI thread and
        /// passes the GeoPositionStatusChangedEventArgs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MyPositionChanged(e));
        }

        /// <summary>
        /// Custom method called from the PositionChanged event handler
        /// </summary>
        /// <param name="e"></param>
        void MyPositionChanged(GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            // Update the TextBlocks to show the current location
            LatitudeTextBlock.Text = e.Position.Location.Latitude.ToString("0.000");
            LongitudeTextBlock.Text = e.Position.Location.Longitude.ToString("0.000");

            //Imposto la defaultlocation a quella dell'utente
            UserLocation = e.Position.Location;

            CenterLocation();

            //todo: update pushpin location
            PushpinModel pushpinToRemove = Pushpins.Where(p => p.TypeName == "UserLocation").FirstOrDefault();
            Pushpins.Remove(pushpinToRemove);
            PushpinModel newPP = new PushpinModel
            {
                Location = new GeoCoordinate() { Latitude = e.Position.Location.Latitude, Longitude = e.Position.Location.Longitude },
                TypeName = "UserLocation",
                Icon = new Uri("/Resources/Icons/Pushpins/PushpinLocation.png", UriKind.Relative),
                BoxID = "0",
                Address = "La tua posizione"
            };
            Pushpins.Add(newPP);
        }

        #endregion

        #region BOXES

        private int selectedIndex = 0;

        static string serviceUriString =
            "http://www.dovesibutta.com/Services/OData.svc/";

        // Declare the service root URI.
        private Uri svcRootUri =
            new Uri(serviceUriString, UriKind.Absolute);


        public bool IsBoxDataLoaded
        {
            get;
            private set;
        }



        // Declare our private binding collection.
        private DataServiceCollection<Box> _boxes;

        // Declare the DataServiceContext as private.
        private DoveSiButtaEntities _context;

        // Public collection used for data binding.
        public DataServiceCollection<Box> Boxes
        {
            get
            {
                return _boxes;
            }
            set
            {
                _boxes = value;

                // Report the change in the binding collection.
                NotifyPropertyChanged("Boxes");

                // Register a handler for the LoadCompleted event.
                _boxes.LoadCompleted +=
                    new EventHandler<LoadCompletedEventArgs>(Boxes_LoadCompleted);
            }
        }

        // Handles the LoadCompleted event.
        private void Boxes_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                // Make sure that we load all pages of the Customers feed.
                if (_boxes.Continuation != null)
                {
                    // Request the next page from the data service.
                    _boxes.LoadNextPartialSetAsync();
                }
                else
                {
                    // All pages are loaded.
                    IsBoxDataLoaded = true;

                    foreach (Box b in Boxes)
                    {

                        CreateBoxPushpin(b);
                    }
                }
            }
            else
            {
                if (MessageBox.Show(e.Error.Message, "Retry request?",
                    MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                {
                    this.LoadBoxesForType(1);
                }
            }
        }


        public void LoadBoxesForType(int type)
        {
            // Sample data; replace with real data
            //TODO: Load Dinners here
            //maps api key

            // Instantiate the context and binding collection.
            if (_context == null)
                _context = new DoveSiButtaEntities(svcRootUri);

            Boxes = new DataServiceCollection<Box>(_context);

            var query = from boxes in _context.Boxes
                        where boxes.BoxType.Contains(type.ToString())
                        select boxes;

            //var query = from boxes in _context.Boxes select boxes;

            //            var query = from orderByCustomer in context.Orders
            //where orderByCustomer.Customers.CustomerID == this.customerId.Text
            //select orderByCustomer;




            // Load the data from the PhotoInfo feed.
            //Dinners.LoadAsync(new Uri("/Dinners", UriKind.Relative));
            Boxes.LoadAsync(query);

        }


        #endregion


    }
}